<?php

namespace app\admin\controller\import;

use app\common\controller\Backend;
use think\Config;
use think\Db;
use app\admin\controller\import\ExcelDataProcessor;
use app\admin\controller\import\ImportHelper;
use think\Exception;
use think\exception\PDOException;
use think\exception\ValidateException;
use think\Log as Logs;

/**
 * 数据导入主控制器
 * 负责处理数据导入的HTTP请求和业务流程控制
 */
class Log extends Backend
{
    /**
     * 模型对象
     * @var \app\admin\model\import\Log
     */
    protected $model = null;
    
    /**
     * 数据限制配置
     */
    protected $dataLimit = true;
    protected $dataLimitField = 'admin_id';
    
    /**
     * 验证配置 
     */
    protected $modelValidate = true;
    protected $dataLimitFieldAutoFill = true;

    /**
     * 初始化方法
     * 设置模型和视图数据
     */
    public function _initialize()
    {
        parent::_initialize();
        $this->model = new \app\admin\model\import\Log;
        $this->view->assign("statusList", $this->model->getStatusList());
        
        // 获取排除表配置
        $config = get_addon_config('import');
        $exclude = explode("\n", $config['exclude']);
        $exclude = array_map('trim', $exclude);
        
        // 构建表列表
        $tableList = ['' => '请选择'];
        $list = Db::query("SHOW TABLES");
        foreach ($list as $row) {
            $tableName = reset($row);
            if (!in_array($tableName, $exclude)) {
                $tableInfo = Db::query("SHOW TABLE STATUS LIKE '{$tableName}'");
                $tableList[$tableName] = $tableName . str_repeat('&nbsp;', 6) . $tableInfo[0]['Comment'];
            }
        }
        
        $this->view->assign([
            "hidden_num" => $this->model->where('status', 'hidden')->count(),
            "tableList" => $tableList,
            "table" => $this->request->request('table') ? Config::get('database.prefix') . $this->request->request('table') : ""
        ]);
    }

    /**
     * 添加导入任务
     * @return mixed
     */
    public function add()
    {
        if ($this->request->isPost()) {
            $params = $this->request->post("row/a");
            $step = $params['step'] ?? 0;
            
            if ($params) {
                $params = $this->preExcludeFields($params);
                
                // 自动填充管理员ID
                if ($this->dataLimit && $this->dataLimitFieldAutoFill) {
                    $params[$this->dataLimitField] = $this->auth->id;
                }
                
                $result = false;
                Db::startTrans();
                try {
                    // 模型验证
                    if ($this->modelValidate) {
                        $name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
                        $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : $name) : $this->modelValidate;
                        $this->model->validateFailException(true)->validate($validate);
                    }
                    
                    // 新建表检查
                    if (!empty($params['newtable'])) {
                        $prefix = Config::get('database.prefix');
                        $table = $prefix . $params['newtable'];
                        if (Db::query("SHOW TABLES LIKE '{$table}'")) {
                            $this->error(__($params['newtable'] . '表已经存在'));
                        }
                    } elseif (empty($params['table'])) {
                        $this->error('未选择目标表');
                    }

                    // 处理文件数据
                    $fileData = $this->fileData($params);
                    $fileData['params'] = http_build_query($params);
                    $fileData['newtable'] = $params['newtable'] ?? '';
                    
                    if (!$step) {
                        $this->success('匹配到' . $fileData['count'] . '列，开始预览', '', $fileData);
                    }
                    
                    // 准备插入数据
                    $insert = $fileData['insert'];
                    $fieldArr = $fileData['fieldArr'];
                    
                    // 自动填充admin_id
                    $has_admin_id = in_array('admin_id', $fieldArr);
                    if ($has_admin_id) {
                        foreach ($insert as &$val) {
                            if (empty($val['admin_id'])) {
                                $val['admin_id'] = $this->auth->isLogin() ? $this->auth->id : 0;
                            }
                        }
                    }
                    
                    // 执行导入
                    $prefix = Config::get('database.prefix');
                    $count = 0;
                    $skipCount = 0;
                    $errorLogs = [];
                    
                    if (!empty($params['update'])) {
                        foreach ($insert as &$val) {
                            try {
                                $count += Db::name(str_replace($prefix, "", $params['table']))
                                    ->where($params['update'], $val['pid'])
                                    ->update($val);
                            } catch (PDOException $e) {
                                $skipCount++;
                                $msg = $e->getMessage();
                                if (preg_match("/.+Integrity constraint violation: 1062 Duplicate entry '(.+)' for key '(.+)'/is", $msg, $matches)) {
                                    $msg = "包含【{$matches[1]}】的记录已存在，已跳过";
                                }
                                $errorLog = "[导入更新错误] " . $msg . " 数据: " . json_encode($val, JSON_UNESCAPED_UNICODE);
                                Logs::write($errorLog, 'error');
                                $errorLogs[] = $errorLog;
                            } catch (\Exception $e) {
                                $skipCount++;
                                $errorLog = "[导入更新错误] " . $e->getMessage() . " 数据: " . json_encode($val, JSON_UNESCAPED_UNICODE);
                                Logs::write($errorLog, 'error');
                                $errorLogs[] = $errorLog;
                            }
                        }
                    } else {
                        if (!empty($params['to'])) {
                            $file = Db::name('attachment')->where('url', $fileData['path'])->find();
                            $this->fieldModel = new \app\admin\model\salary\Field;
                            $fields = $this->fieldModel->where('name', 'not in', ['pid', 'name', 'status', 'create_time', 'update_time', 'deletetime'])->select();
                            
                            $insertData = [];
                            foreach ($insert as $val) {
                                $toData = [];
                                foreach ($fields as $field) {
                                    if (isset($val[$field['name']])) {
                                        $toData[] = [
                                            'pid' => $val['pid'],
                                            'name' => $val['name'],
                                            'type' => $field['name'],
                                            'type_name' => $field['desc'],
                                            'field_type' => $field['type'],
                                            'je' => $val[$field['name']],
                                            'filename' => $file['filename'],
                                            'sha1' => $file['sha1'],
                                            'createtime' => time()
                                        ];
                                    }
                                }
                                $insertData = array_merge($insertData, $toData);
                            }
                            
                            try {
                                Db::name(str_replace($prefix, "", $params['to']))->where('sha1', $file['sha1'])->delete();
                                $res = Db::name(str_replace($prefix, "", $params['to']))->insertAll($insertData);
                                $count = count($insert);
                            } catch (PDOException $e) {
                                $skipCount++;
                                $msg = $e->getMessage();
                                if (preg_match("/.+Integrity constraint violation: 1062 Duplicate entry '(.+)' for key '(.+)'/is", $msg, $matches)) {
                                    $msg = "包含【{$matches[1]}】的记录已存在，已跳过";
                                }
                                $errorLog = "[导入错误] " . $msg;
                                Logs::write($errorLog, 'error');
                                $errorLogs[] = $errorLog;
                            } catch (\Exception $e) {
                                $skipCount++;
                                $errorLog = "[导入错误] " . $e->getMessage();
                                Logs::write($errorLog, 'error');
                                $errorLogs[] = $errorLog;
                            }
                        } else {
                            // 逐条插入数据以避免因某条数据错误而导致整批数据失败
                            foreach ($insert as $row) {
                                try {
                                    // 处理表名
                                    // 1. 获取数据库配置信息
                                    $dbConfig = Config::get('database');
                                    $prefix = $dbConfig['prefix'];
                                    $database = $dbConfig['database'];
                                    
                                    // 2. 处理表名 - 确保使用正确格式
                                    $tableName = $params['table'];
                                    
                                    // 检查表名是否已包含前缀
                                    if (strpos($tableName, $prefix) === 0) {
                                        // 已包含前缀，直接使用
                                        $fullTableName = $tableName;
                                    } else {
                                        // 不包含前缀，添加前缀
                                        $fullTableName = $prefix . $tableName;
                                    }
                                    
                                    // 确保表存在
                                    $checkTableSql = "SHOW TABLES LIKE '{$fullTableName}'";
                                    $tableExists = Db::query($checkTableSql);
                                    
                                    if (empty($tableExists)) {
                                        $errorLog = "[导入错误] 表 {$fullTableName} 不存在，请检查表名是否正确";
                                        Logs::write($errorLog, 'error');
                                        $skipCount++;
                                        continue; // 跳过此条记录处理下一条
                                    }
                                    
                                    // 调试日志
                                    Logs::write("[表名调试] 原始表参数: {$params['table']}, 完整表名: {$fullTableName}, 前缀: {$prefix}, 数据库: {$database}", 'info');
                                    
                                    // 忽略"配送工程师"字段
                                    if (isset($row['配送工程师'])) {
                                        unset($row['配送工程师']);
                                    }
                                    
                                    $fields = array_keys($row);
                                    
                                    // 处理值数组，特别处理null值避免PDO::quote()警告
                                    $values = [];
                                    $valuesSql = [];
                                    
                                    foreach ($row as $field => $value) {
                                        if ($value === null) {
                                            $valuesSql[] = 'NULL'; // 直接在SQL中使用NULL关键字
                                        } else {
                                            $values[] = $value;
                                            $valuesSql[] = '?';
                                        }
                                    }
                                    
                                    // 构建SQL语句，null值使用直接的NULL关键字，非null值使用参数绑定
                                    $sql = "INSERT INTO `{$fullTableName}` (`" . implode("`, `", $fields) . "`) VALUES (" . implode(", ", $valuesSql) . ")";
                                    
                                    // 记录完整SQL和绑定参数
                                    $debugSql = $sql;
                                    foreach ($values as $val) {
                                        $debugSql = preg_replace('/\?/', is_string($val) ? "'" . addslashes($val) . "'" : $val, $debugSql, 1);
                                    }
                                    Logs::write("[SQL调试] 执行SQL: {$debugSql}", 'info');
                                    
                                    try {
                                        // 执行SQL语句，只传递非null的参数
                                        $res = Db::execute($sql, $values);
                                        
                                        if ($res) {
                                            $count++;
                                        }
                                    } catch (PDOException $e) {
                                        $skipCount++;
                                        $msg = $e->getMessage();
                                        if (preg_match("/.+Integrity constraint violation: 1062 Duplicate entry '(.+)' for key '(.+)'/is", $msg, $matches)) {
                                            $msg = "包含【{$matches[1]}】的记录已存在，已跳过";
                                        }
                                        // 调试信息，记录详细错误
                                        $debugData = [];
                                        $debugData['error'] = $msg;
                                        $debugData['data'] = $row;
                                        $debugData['sql'] = $debugSql;
                                        $errorLog = "[导入插入错误] " . $msg . " 数据: " . json_encode($row, JSON_UNESCAPED_UNICODE) . " SQL: " . $debugData['sql'];
                                        Logs::write($errorLog, 'error');
                                        $errorLogs[] = $errorLog;
                                    } catch (\Exception $e) {
                                        $skipCount++;
                                        $msg = $e->getMessage();
                                        // 调试信息，记录详细错误
                                        $debugData = [];
                                        $debugData['error'] = $msg;
                                        $debugData['data'] = $row;
                                        $debugData['sql'] = $debugSql;
                                        $errorLog = "[导入插入错误] " . $msg . " 数据: " . json_encode($row, JSON_UNESCAPED_UNICODE) . " SQL: " . $debugData['sql'];
                                        Logs::write($errorLog, 'error');
                                        $errorLogs[] = $errorLog;
                                    }
                                } catch (PDOException $e) {
                                    $skipCount++;
                                    $msg = $e->getMessage();
                                    if (preg_match("/.+Integrity constraint violation: 1062 Duplicate entry '(.+)' for key '(.+)'/is", $msg, $matches)) {
                                        $msg = "包含【{$matches[1]}】的记录已存在，已跳过";
                                    }
                                    // 调试信息，记录详细错误
                                    $debugData = [];
                                    $debugData['error'] = $msg;
                                    $debugData['data'] = $row;
                                    $debugData['sql'] = $debugSql;
                                    $errorLog = "[导入插入错误] " . $msg . " 数据: " . json_encode($row, JSON_UNESCAPED_UNICODE) . " SQL: " . $debugData['sql'];
                                    Logs::write($errorLog, 'error');
                                    $errorLogs[] = $errorLog;
                                } catch (\Exception $e) {
                                    $skipCount++;
                                    $msg = $e->getMessage();
                                    // 调试信息，记录详细错误
                                    $debugData = [];
                                    $debugData['error'] = $msg;
                                    $debugData['data'] = $row;
                                    $debugData['sql'] = $debugSql;
                                    $errorLog = "[导入插入错误] " . $msg . " 数据: " . json_encode($row, JSON_UNESCAPED_UNICODE) . " SQL: " . $debugData['sql'];
                                    Logs::write($errorLog, 'error');
                                    $errorLogs[] = $errorLog;
                                }
                            }
                        }
                    }
                    
                    Db::commit();
                    
                    // 保存导入记录
                    $params['status'] = 'normal';
                    $result = $this->model->allowField(true)->save($params);
                    
                    $tip = !empty($params['update']) ? '成功更新' : '成功新增';
                    $message = $tip . $count . '条记录';
                    if ($skipCount > 0) {
                        $message .= "，跳过{$skipCount}条错误记录，详情请查看日志";
                    }
                    $this->success($message, '', ['count' => $count, 'skipCount' => $skipCount]);
                    
                } catch (ValidateException $e) {
                    Db::rollback();
                    $this->error($e->getMessage());
                } catch (PDOException $e) {
                    Db::rollback();
                    $msg = $e->getMessage();
                    if (preg_match("/.+Integrity constraint violation: 1062 Duplicate entry '(.+)' for key '(.+)'/is", $msg, $matches)) {
                        $msg = "导入失败，包含【{$matches[1]}】的记录已存在";
                    }
                    $this->error($msg);
                } catch (Exception $e) {
                    Db::rollback();
                    $this->error($e->getMessage());
                }
            }
            $this->error(__('Parameter %s can not be empty', ''));
        }
        
        $this->view->assign([
            "update" => $this->request->request('update'),
            "to" => $this->request->request('to')
        ]);
        return $this->view->fetch();
    }

    /**
     * 编辑导入配置
     * @param string $ids 记录ID
     * @return mixed
     */
    public function edit($ids = null)
    {
        $row = $this->model->get($ids);
        if (!$row) {
            $this->error(__('No Results were found'));
        }
        
        // 数据权限检查
        $adminIds = $this->getDataLimitAdminIds();
        if (is_array($adminIds) && !in_array($row[$this->dataLimitField], $adminIds)) {
            $this->error(__('You have no permission'));
        }
        
        if ($this->request->isPost()) {
            $params = $this->request->post("row/a");
            if ($params) {
                $params = $this->preExcludeFields($params);
                $result = false;
                Db::startTrans();
                try {
                    $params['newtable'] = '';
                    $fileData = $this->fileData($params);
                    $fileData['params'] = http_build_query($params);
                    $this->success('匹配到' . $fileData['count'] . '列，开始预览', '', $fileData);
                    Db::commit();
                } catch (ValidateException $e) {
                    Db::rollback();
                    $this->error($e->getMessage());
                } catch (PDOException $e) {
                    Db::rollback();
                    $msg = $e->getMessage();
                    if (preg_match("/.+Integrity constraint violation: 1062 Duplicate entry '(.+)' for key '(.+)'/is", $msg, $matches)) {
                        $msg = "导入失败，包含【{$matches[1]}】的记录已存在";
                    }
                    $this->error($msg);
                } catch (Exception $e) {
                    Db::rollback();
                    $this->error($e->getMessage());
                }
                
                if ($result !== false) {
                    $this->success('设置成功', url('doimport', ['ids' => $row['id']]));
                } else {
                    $this->error(__('No rows were updated'));
                }
            }
            $this->error(__('Parameter %s can not be empty', ''));
        }
        
        $row['params'] = http_build_query([
            'table' => $row['table'],
            'row' => $row['row'],
            'head_type' => $row['head_type'],
            'path' => $row['path'],
        ]);
        
        $this->view->assign("row", $row);
        return $this->view->fetch();
    }

    /**
     * 预览导入数据
     * @return \think\response\Json
     */
    public function preview()
    {
        $params = $this->request->post("row/a");
        if (!isset($params["path"])) {
            $this->error(__('No Results were found'));
        }
        
        if ($this->request->isAjax()) {
            $fileData = $this->fileData($params);

            if (isset($params["columns"])) {
                return json(["code" => 1, "data" => $fileData['field']]);
            }
            return json([
                "code" => 1, 
                'data' => [
                    'field' => $fileData['field'],
                    'data' => $fileData['data'],
                    'fieldArr' => $fileData['fieldArr']
                ]
            ]);
        }
    }

    /**
     * 处理文件数据
     * @param array $params 导入参数
     * @return array
     */
    protected function fileData($params)
    {
        $processor = new ExcelDataProcessor();
        return $processor->process(
            $params['path'],
            $params['row'],
            $params['table'],
            $params['head_type'],
            $params['newtable'] ?? ''
        );
    }
}